import { DragSource } from "react-dnd";
import { getElement } from "@design/core/utils/dom";

const dragSpec = {
  beginDrag(props) {
    let { node } = props;
    let isNew = false;
    if (typeof node === "function") {
      node = node();
      isNew = true;
    }
    if (!isNew) {
      const element = getElement(node.key);
      return { node, isNew, element };
    }
    return { node, isNew };
  },
  endDrag(props, monitor) {
    if (!monitor.didDrop()) {
      return;
    }
    const { node, isNew } = monitor.getItem();
    const { target, editor, offset = { x: 0, y: 0 } } = monitor.getDropResult();
    const position = node.position.set("x", offset.x).set("y", offset.y);
    if (isNew) {
      editor.insertNodeByKey(
        node.set("position", position),
        target.key,
        target.nodes.size
      );
      return;
    }

    editor.updateNode(node, { position });
    editor.moveNode(node.key, target.key, target.nodes.size);
  },
};

function DragDecorator(options = {}) {
  const { type = "block", dropEffect = "move", offset = {} } = options;
  function collect(connect, monitor) {
    const connectDragSource = (node, options) => {
      return connect.dragSource()(node, { dropEffect, ...options });
    };
    const connectDragPreview = (node, options) => {
      return connect.dragPreview()(node, { ...offset, ...options });
    };
    return {
      connectDragPreview,
      connectDragSource,
      isDragging: monitor.isDragging(),
    };
  }
  return Comp => {
    return DragSource(type, dragSpec, collect)(Comp);
  };
}

export default DragDecorator;
